Skip to content

feat: 도서 상세 화면 개편#269

Merged
doyeonk429 merged 21 commits intodevelopfrom
BOOK-499-feature/#268
Feb 14, 2026
Merged

feat: 도서 상세 화면 개편#269
doyeonk429 merged 21 commits intodevelopfrom
BOOK-499-feature/#268

Conversation

@doyeonk429
Copy link
Member

@doyeonk429 doyeonk429 commented Feb 9, 2026

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)
  • 🎨 style (코드 스타일 수정)

📙 작업 내역

  • 도서 상세 화면 개편 작업
  • 자잘한 디자인, 간격 수정
  • SeedReport 부분 전면 수정
  • API v2, record fetch, seed 수정 반영
  • RecordCell 디자인 수정

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

케이스 케이스 케이스
Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 39 19 Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 39 08 Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 37 48
Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 37 34 Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 37 13 Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 36 21
Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 36 17 Simulator Screenshot - ReedTest_26 2 - 2026-02-09 at 15 37 01 Simulator Screenshot - ReedTest_26 2 - 2026-02-08 at 22 59 06
  • '기타' 부분 그래프 예시 동작 영상
Simulator.Screen.Recording.-.ReedTest_26.2.-.2026-02-09.at.15.24.09.mp4

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다
  • PR 제목이 컨벤션에 맞습니다
  • 관련 이슈 번호를 작성했습니다
  • 기능이 정상적으로 작동합니다
  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트 (선택)

  • v2baseURL 추가 필요합니다!

Summary by CodeRabbit

  • 새로운 기능

    • 감정 카테고리 "기타" 추가 및 관련 시각·텍스트 지원
    • 감정 그래프(비율 기반)와 항목 뷰 추가, 확장 가능한 감정 리포트 섹션 도입
    • 기록 목록 응답에 대표 감정(mainEmotion) 포함 및 책 상세에 감정 헤더 표시
    • 페이지 표시 포맷 추가 ("123p" / "-p")
  • 개선사항

    • 색상 시스템 확장(오렌지·바이올렛)과 그래프용 색상 매핑 강화
    • 레이아웃·정렬 및 리스트/셀 UI 개선, 페이징/정렬 처리 보완

@doyeonk429 doyeonk429 self-assigned this Feb 9, 2026
@github-actions github-actions bot requested a review from clxxrlove February 9, 2026 06:43
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Walkthrough

API V2 엔드포인트가 도입되고 RecordFetchResult 도메인 모델로 반환 형태가 통합되었습니다. 감정(etс) 및 색상 팔레트 확장이 이루어졌고, 도서 상세 화면에 씨앗 기반 그래프·리포트 UI와 관련 데이터 흐름(mainEmotion) 연결이 추가되었습니다.

Changes

Cohort / File(s) Summary
API / Config / Core util
src/Projects/BKCore/Sources/Extension/Optional.swift, src/Projects/BKData/Sources/API/RecordAPI.swift, src/Projects/BKData/Sources/Constant/APIConfig.swift, src/SupportingFiles/Booket/Info.plist
Optional → 페이지 문자열 변환(toPageString) 추가. RecordAPI의 .fetch/.seed 케이스에서 APIConfig.baseV2URL 사용으로 엔드포인트 분기 추가. APIConfig.baseV2URL 및 Info.plist BASE_API_V2_URL 항목 추가.
Response DTOs (V2)
src/Projects/BKData/Sources/DTO/Response/DetailRecordResponseDTO.swift, src/Projects/BKData/Sources/DTO/Response/FetchRecordResponseDTO.swift, src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift
API V2 DTO(DetailRecordV2ResponseDTO) 추가 및 toRecordInfo() 매핑, Fetch 응답이 V2 DTO로 변경(대표 감정 필드 representativeEmotion 추가), Primary/Detail emotion DTO 추가.
데이터/레포지토리
src/Projects/BKData/Sources/Repository/DefaultRecordRepository.swift
레포지토리 fetch 반환형을 튜플 → RecordFetchResult로 변경하고 응답 매핑에 mainEmotion 포함하도록 조정.
도메인 모델/인터페이스
src/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift, src/Projects/BKDomain/Sources/Entity/Emotion.swift, src/Projects/BKDomain/Sources/Interface/Repository/RecordRepository.swift, src/Projects/BKDomain/Sources/Interface/Usecase/FetchRecordsUseCase.swift, src/Projects/BKDomain/Sources/UseCase/DefaultFetchRecordsUseCase.swift
RecordFetchResult 구조체 추가(대응 필드 포함), Emotionetc 케이스 추가. Repository/UseCase/UseCase 구현의 fetch/execute 시그니처가 RecordFetchResult 반환으로 변경.
프레젠테이션 모델 변경
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/BookDetailItem.swift, src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift
BookDetailItem.pageInt?로 변경. EmotionSeedetc 추가 및 관련 매핑·이미지·색상·graphTintColor·설명 텍스트 등 확장.
BookDetail 뷰 및 셀 업데이트
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailView.swift, src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewCell.swift, src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewHeader.swift
BookDetailView: 페이지 정렬(nil 처리), 레이아웃 마진/상수 조정, applySeedHeader(with:) 추가. Cell: 감정 아이콘 제거, 페이지·태그 레이블로 재구성. Header: 타이틀 강조색 변경.
Seed 컴포넌트 추가/리팩토링
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedGraphView.swift, src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedItemView.swift, src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift
SeedGraphView/SeedItemView 신규 추가. SeedReportView 대규모 리팩토링으로 헤더·접기/펼치기 UI, 그래프·목록 표시 도입 및 setEmotionHeader/applyGraph API 추가.
뷰모델·뷰컨트롤러 상태 흐름
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/BookDetailViewController.swift, src/Projects/BKPresentation/Sources/MainFlow/BookDetail/ViewModel/BookDetailViewModel.swift
ViewModel 상태에 mainEmotion 추가, fetchRecordsSuccessed 액션에 mainEmotion 전달. ViewController가 mainEmotion 구독해 Seed 헤더 적용 로직 추가.
디자인 시스템(색상)
src/Projects/BKDesign/Sources/Extensions/UIColor+.swift, src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKAtomicColor.swift, src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKSemanticColor.swift
UIColor 헬퍼 추가. BKAtomicColor.Blue hex 업데이트, Orange/Violet 팔레트 및 color 프로퍼티 추가. BKSemanticColorEmotionGraphTint 열거형 및 etc 감정 처리 확장.
기타 UI 안정성 변경
src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift, src/Projects/BKPresentation/Sources/MainFlow/NoteCompletion/View/AppreciationResultView.swift
감정 매핑 switch에 default 케이스 추가로 안전성 향상.

Sequence Diagram(s)

sequenceDiagram
    participant View as BookDetailView
    participant VC as BookDetailViewController
    participant VM as BookDetailViewModel
    participant UC as FetchRecordsUseCase
    participant Repo as DefaultRecordRepository
    participant API as RecordAPI
    participant Resp as API Response

    View->>VC: 초기 로드/스크롤 -> fetch page 0 액션 디스패치
    VC->>VM: dispatch(.fetchRecords(page: 0))
    VM->>UC: execute(id, page: 0)
    UC->>Repo: fetch(bookId, sortType, page: 0)
    Repo->>API: 요청 `.fetch` (uses APIConfig.baseV2URL)
    API->>Resp: HTTP 응답 (V2 DTO)
    Resp->>Repo: DTO → RecordFetchResult(mainEmotion 포함) 변환
    Repo->>UC: RecordFetchResult 반환
    UC->>VM: 성공 결과 전달(RecordFetchResult)
    VM->>VC: 상태 발행(mainEmotion 포함)
    VC->>View: applySeedHeader(mainEmotion) / SeedReportView.applyGraph(...)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ⚠️ Unable to check for merge conflicts: Invalid branch name format
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목 '도서 상세 화면 개편'은 변경사항의 주요 내용을 명확하게 반영합니다. 도서 상세 화면 전체 개편, SeedReport 부분 수정, API v2 적용, RecordCell 디자인 수정 등 모든 변경사항이 이 제목에 포함됩니다.
Linked Issues check ✅ Passed 코드 변경사항이 이슈 #268의 모든 작업 항목을 충족합니다: (1) 기록 0개 케이스 처리 [BookDetailView 업데이트], (2) 씨앗카드 디자인 [SeedReportView, EmotionSeed 개편], (3) 씨앗카드 folding 애니메이션 [SeedReportView.toggleExpansion], (4) 기록 셀 디자인 [BookDetailViewCell 개편], (5) 씨앗 카드 progressbar [SeedGraphView 신규 추가].
Out of Scope Changes check ✅ Passed 모든 변경사항이 도서 상세 화면 UI 개편 범위 내에 있습니다. API v2 적용(RecordAPI, APIConfig, DTO 변경), 도메인 모델 업데이트(RecordFetchResult, Emotion.etc), 색상 시스템 확장(Orange, Violet 컬러), 새로운 감정 카테고리(etc/'기타')는 모두 이 목표를 지원하는 필요한 변경입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BOOK-499-feature/#268
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch BOOK-499-feature/#268
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift (3)

129-136: setEmotionHeader(with:)에서 파라미터 이름을 섀도잉하고 있습니다.

Line 130에서 let emotion = EmotionSeed.from(emotion: emotion)으로 파라미터 emotion: Emotion을 로컬 변수 emotion: EmotionSeed로 섀도잉합니다. 동작에는 문제 없지만, 타입이 다른 동명 변수는 가독성을 떨어뜨릴 수 있습니다.

♻️ 변수명 구분 제안
 func setEmotionHeader(with emotion: Emotion) {
-    let emotion = EmotionSeed.from(emotion: emotion)
-    let emotionText = "\'\(emotion.rawValue)\'"
-    emotionImageView.image = emotion.circleImage
-    reportLabel.highlightColor = emotion.color
-    reportLabel.setText(text: "\(emotionText) \(emotion.descriptionText)")
+    let emotionSeed = EmotionSeed.from(emotion: emotion)
+    let emotionText = "\'\(emotionSeed.rawValue)\'"
+    emotionImageView.image = emotionSeed.circleImage
+    reportLabel.highlightColor = emotionSeed.color
+    reportLabel.setText(text: "\(emotionText) \(emotionSeed.descriptionText)")
     reportLabel.highlightedWord = emotionText
 }

138-157: applyGraph(with:)uniquingKeysWith에서 중복 시 마지막 값만 유지됩니다.

Line 145에서 seeds 배열에 동일 nameSeed가 여러 개 존재할 경우 마지막 값만 사용되고 나머지는 무시됩니다. 의도된 동작이라면 괜찮지만, 만약 count를 합산해야 하는 경우라면 로직 수정이 필요합니다. 또한 미사용 파라미터 first_로 대체하면 의도가 더 명확해집니다.

♻️ 미사용 파라미터 정리
-let seedDict = Dictionary(seeds.map { ($0.name, $0) }, uniquingKeysWith: { first, last in last })
+let seedDict = Dictionary(seeds.map { ($0.name, $0) }, uniquingKeysWith: { _, last in last })

160-173: @objc private funcprivate extension 내에서 private 수식어가 중복됩니다.

private extension 블록 내 모든 멤버는 이미 private 접근 수준을 갖습니다. @objc와 함께 사용할 때 컴파일은 되지만 중복 명시입니다.

또한 애니메이션 로직 자체는 UIStackViewisHidden 토글 + alpha 조합으로 잘 구현되어 있습니다.

♻️ 중복 접근 수식어 제거
 private extension SeedReportView {
-    `@objc` private func toggleExpansion() {
+    `@objc` func toggleExpansion() {
         isExpanded.toggle()

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift (1)

176-176: ⚠️ Potential issue | 🟠 Major

hashValue를 view tag로 사용하는 것은 충돌 위험이 있습니다

hashValue는 Swift에서 고유성이 보장되지 않으며, 서로 다른 값이 동일한 hashValue를 가질 수 있습니다. 이 경우 emotionTapped에서 잘못된 감정이 선택될 수 있습니다.

Emotion이 이미 CaseIterable을 준수하므로, Emotion.allCases.firstIndex(of:)를 사용하여 안정적인 정수 식별자를 얻을 수 있습니다:

wrapperView.tag = Emotion.allCases.firstIndex(of: emotion) ?? 0

그리고 emotionTapped에서:

guard let tappedView = sender.view,
      let emotion = Emotion.allCases[safe: tappedView.tag] else {
    return
}

또는 더 간단하게:

let emotion = Emotion.allCases[tappedView.tag]
src/Projects/BKDomain/Sources/Entity/Emotion.swift (1)

3-9: ⚠️ Potential issue | 🟠 Major

etc 케이스는 올바르게 추가되었으나 일부 switch 문에서 명시적 처리 필요합니다.

EmotionRegistrationView.swift 라인 150과 AppreciationResultView.swift 라인 24의 switch 문이 default 케이스로 .etc를 암묵적으로 처리하고 있습니다. 다음 파일들에서 .etc 케이스를 명시적으로 추가하세요:

  • EmotionRegistrationView.swift 라인 150: case .etc를 추가하여 명시적으로 이미지를 지정
  • AppreciationResultView.swift 라인 24: case .etc를 추가하여 명시적으로 색상을 반환

EmotionSeed는 모든 computed property에서 .etc를 올바르게 처리하고 있습니다 (baseColor에서는 EmotionBase.etc가 없으므로 .bkEmotionColor(.etc)를 사용하는 것으로 의도적으로 구현됨).

src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift (1)

45-53: ⚠️ Potential issue | 🟡 Minor

.etcbaseColor가 다른 케이스와 다른 패턴으로 처리되고 있습니다.

다른 케이스들은 bkEmotionBaseColor()(연한 배경색)를 사용하지만, .etcbkEmotionColor(.etc)(일반 텍스트 색상)를 사용합니다. EmotionBase.etc 케이스가 없어서 이렇게 처리한 것으로 보이나, baseColorcolor와 동일한 값이 되어 시각적으로 배경색 역할을 하지 못할 수 있습니다.

🤖 Fix all issues with AI agents
In `@src/Projects/BKData/Sources/Constant/APIConfig.swift`:
- Around line 17-22: The fatalError message in the static property baseV2URL is
wrong — it reads "BKData.BASE_API_URL" while the code is loading the
"BASE_API_V2_URL" key; update the fatalError in the closure (the guard that
calls bundle.object(forInfoDictionaryKey:)) to reference the correct key name
("BASE_API_V2_URL") or include both key and module for clarity so the error
matches the attempted lookup in baseV2URL.

In `@src/Projects/BKData/Sources/DTO/Response/PrimaryEmotionResponseDTO.swift`:
- Around line 5-8: PrimaryEmotionResponseDTO currently decodes displayName
directly as the Emotion enum which will fail if the server string has different
casing/whitespace/locale or unknown values; change displayName in
PrimaryEmotionResponseDTO to decode as String (or implement a custom init(from:)
on PrimaryEmotionResponseDTO) and then map/convert that String to the Emotion
domain enum using a tolerant initializer on Emotion (e.g., trimming,
case-insensitive match, and a fallback case like .other or .unknown); update or
add an Emotion.init?(rawString: String) helper and use it inside
PrimaryEmotionResponseDTO's decoding logic so parsing never throws for
unexpected server values.

In
`@src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift`:
- Around line 72-79: The configure() method currently sets a hardcoded
placeholder via reportLabel.setText(text: "테스트용 텍스트입니다.") which will be visible
if setEmotionHeader(with:) is never called (e.g., mainEmotion is nil); remove
the placeholder and instead handle the empty state by clearing the label or
hiding the whole view when no emotion is present: update configure() to not set
the test string, ensure setEmotionHeader(with:) populates reportLabel when
provided, and add logic (e.g., in setEmotionHeader(with:) or a new
updateEmptyState() helper) to call reportLabel.setText(text: "") or
self.isHidden = true when mainEmotion is nil so the placeholder is never shown.
🧹 Nitpick comments (11)
src/Projects/BKPresentation/Sources/MainFlow/Note/View/EmotionRegistrationView.swift (1)

26-27: default 대신 명시적 케이스 매칭 고려

새로운 .etc 감정 케이스 추가로 인해 default가 필요해진 것으로 보입니다. 하지만 default를 사용하면 향후 Emotion에 새로운 케이스가 추가될 때 컴파일러 경고 없이 자동으로 warmEmotion으로 매핑되어 버그를 놓칠 수 있습니다.

default 대신 case .etc:(또는 현재 해당하는 케이스)를 명시적으로 매칭하면, 새 케이스 추가 시 컴파일 에러로 누락을 방지할 수 있습니다.

제안
-        default:
+        case .etc:
             imageView.image = BKImage.Graphics.warmEmotion

switch 문 모두 동일하게 적용하면 됩니다.

Also applies to: 159-160

src/Projects/BKCore/Sources/Extension/Optional.swift (1)

3-3: 불필요한 UIKit import

이 파일은 UIKit 타입을 사용하지 않습니다. Foundation으로 충분합니다.

♻️ 수정 제안
-import UIKit
+import Foundation
src/Projects/BKPresentation/Sources/MainFlow/NoteCompletion/View/AppreciationResultView.swift (1)

33-34: default 대신 .etc를 명시적으로 매칭하는 것을 고려해 주세요.

현재 default는 향후 Emotion에 새로운 케이스가 추가될 때 컴파일러 경고 없이 .warmth로 매핑됩니다. .etc를 명시적으로 처리하면 새 케이스 추가 시 컴파일 타임에 누락을 감지할 수 있습니다.

♻️ 수정 제안
         case .insight:
             return .insight
-        default:
+        case .etc:
             return .warmth
src/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift (1)

3-3: Foundation import가 불필요해 보입니다.

이 struct는 Foundation 타입을 직접 사용하지 않습니다. RecordInfoEmotion은 같은 모듈 내 타입이므로 import 없이도 접근 가능합니다.

♻️ 제안
-import Foundation
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedItemView.swift (1)

57-62: emotionnil일 때 dot이 투명하게 표시됩니다.

EmotionSeed.from(seed:)nil을 반환하면 dotView.backgroundColornil(투명)이 됩니다. SeedGraphView에서는 같은 경우에 .lightGray 폴백을 사용하고 있어 동작이 일관되지 않습니다. 동일한 폴백 색상 적용을 고려해 주세요.

♻️ 폴백 색상 추가 제안
-        dotView.backgroundColor = emotion?.graphTintColor
+        dotView.backgroundColor = emotion?.graphTintColor ?? .lightGray
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedGraphView.swift (1)

16-16: cornerRadius 매직 넘버.

cornerRadius = 6이 하드코딩되어 있습니다. SeedItemView처럼 BKRadius 디자인 토큰 사용을 권장합니다.

src/Projects/BKDesign/Sources/Foundation/ColorSystem/BKSemanticColor.swift (1)

142-142: Emotion.etc의 resolve 패턴이 다른 케이스들과 일관성이 없습니다.

다른 케이스들은 BKAtomicColor.X.y.color처럼 정적 UIColor를 직접 반환하지만, .etcbkContentColor(.secondary)를 사용하여 traitCollection 기반의 동적 UIColor를 반환합니다. 기능적으로는 동작하지만, resolve(for:) 패턴에서 일관성이 깨집니다. 예를 들어, 다른 곳에서 resolve(for: .light)의 결과가 정적 색상일 것이라 가정하고 비교하는 경우 예상치 못한 동작이 발생할 수 있습니다.

♻️ 직접 atomic color를 반환하도록 변경 제안
-                case .etc: return .bkContentColor(.secondary)
+                case .etc: return BKAtomicColor.Neutral.n500.color
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/Models/EmotionSeed.swift (1)

21-21: .etc 케이스의 이미지 리소스가 다른 감정의 것을 재사용하고 있습니다.

imagesad의 이미지, circleImageinsight의 원형 이미지, cardImagesad의 카드 이미지를 사용하고 있습니다. 의도적인 임시 처리라면 괜찮지만, "기타" 감정에 슬픔이나 깨달음 관련 이미지가 보이면 사용자에게 혼동을 줄 수 있습니다. "기타"용 전용 이미지 에셋이 필요한지 디자인팀과 확인해 보시는 것을 권장합니다.

Also applies to: 31-31, 97-97

src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift (3)

124-129: labelsStackView 높이에 매직 넘버 72가 사용되고 있습니다.

다른 레이아웃 값들은 LayoutConstants에 정의되어 있지만, 이 값만 인라인으로 하드코딩되어 있습니다. 일관성을 위해 상수로 추출하는 것을 권장합니다.

♻️ LayoutConstants에 추가
 enum LayoutConstants {
     // ...
+    static let labelsHeight: CGFloat = 72
     static let graphHeight: CGFloat = 12
     // ...
 }
 labelsStackView.snp.makeConstraints {
     $0.top.equalTo(graphView.snp.bottom).offset(LayoutConstants.labelsTopOffset)
-    $0.height.equalTo(72)
+    $0.height.equalTo(LayoutConstants.labelsHeight)
     $0.horizontalEdges.equalToSuperview()
     $0.bottom.equalToSuperview()
 }

132-139: emotion 파라미터명이 로컬 변수에 의해 가려지고 있습니다(variable shadowing).

Line 132의 파라미터 emotion: Emotion이 line 133의 let emotion = EmotionSeed.from(emotion: emotion)에 의해 가려집니다. 동작에는 문제 없지만 가독성을 위해 로컬 변수명을 분리하는 것이 좋습니다.

♻️ 변수명 분리 제안
 func setEmotionHeader(with emotion: Emotion) {
-    let emotion = EmotionSeed.from(emotion: emotion)
-    let emotionText = "\'\(emotion.rawValue)\'"
-    emotionImageView.image = emotion.circleImage
-    reportLabel.highlightColor = emotion.color
+    let emotionSeed = EmotionSeed.from(emotion: emotion)
+    let emotionText = "\'\(emotionSeed.rawValue)\'"
+    emotionImageView.image = emotionSeed.circleImage
+    reportLabel.highlightColor = emotionSeed.color
     reportLabel.setText(text: "\(emotionText) 감정을 많이 느꼈어요")
     reportLabel.highlightedWord = emotionText
 }

163-177: 접기/펼치기 애니메이션 구현이 적절합니다.

UIStackView의 isHidden 애니메이션과 chevron 회전이 잘 결합되어 있습니다. 다만, 빠른 연속 탭 시 애니메이션 겹침이 발생할 수 있으므로, 필요하다면 UIViewPropertyAnimator나 애니메이션 진행 중 탭 무시 등의 보호 로직을 추가할 수 있습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift`:
- Around line 61-69: The tap target for foldButton is too small (24x24) because
a UITapGestureRecognizer is added directly to the UIImageView in setupView;
increase the hit area to meet the 44x44pt HIG by replacing the UIImageView tap
approach with a larger tappable control or expanding its insets: make foldButton
a UIButton (or wrap the image in a UIButton), set appropriate contentEdgeInsets
to achieve at least 44x44 touchable area, attach the
UITapGestureRecognizer/action to toggleExpansion (or use UIButton.addTarget)
instead of directly on the image view, and ensure headerView layout constraints
for foldButton accommodate the larger hit frame.
🧹 Nitpick comments (2)
src/Projects/BKPresentation/Sources/MainFlow/BookDetail/View/SeedReportView.swift (2)

132-139: emotion 파라미터명을 로컬 변수로 섀도잉하고 있습니다.

Line 133에서 let emotion = EmotionSeed.from(emotion: emotion)으로 파라미터를 같은 이름으로 덮어쓰면 가독성이 떨어집니다.

♻️ 리네이밍 제안
 func setEmotionHeader(with emotion: Emotion) {
-    let emotion = EmotionSeed.from(emotion: emotion)
-    let emotionText = "\'\(emotion.rawValue)\'"
-    emotionImageView.image = emotion.circleImage
-    reportLabel.highlightColor = emotion.color
-    reportLabel.setText(text: "\(emotionText) \(emotion.descriptionText)")
+    let emotionSeed = EmotionSeed.from(emotion: emotion)
+    let emotionText = "\'\(emotionSeed.rawValue)\'"
+    emotionImageView.image = emotionSeed.circleImage
+    reportLabel.highlightColor = emotionSeed.color
+    reportLabel.setText(text: "\(emotionText) \(emotionSeed.descriptionText)")
     reportLabel.highlightedWord = emotionText
 }

163-176: private extension 내의 @objc private func에서 private 키워드가 중복됩니다.

private extension 내 멤버는 이미 private이므로 함수에 별도 private 지정이 불필요합니다.

♻️ 중복 접근 제어자 제거
-    `@objc` private func toggleExpansion() {
+    `@objc` func toggleExpansion() {

Copy link
Member

@clxxrlove clxxrlove left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고 많으셨어요 ~~!!

@doyeonk429 doyeonk429 merged commit 193f034 into develop Feb 14, 2026
3 checks passed
@doyeonk429 doyeonk429 deleted the BOOK-499-feature/#268 branch February 14, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOOK-499/feat] 도서 상세 화면 UI 개선작업

2 participants